package watcher

import (
	"github.com/shirou/gopsutil/disk"
	"time"
	"watcher/client/config"
)

type IOWatcher struct {
	Done     chan struct{}
	Duration time.Duration
}

func (watcher *IOWatcher) Watch() <-chan *WatchData {
	dataChan := make(chan *WatchData, 10)
	go watcher.watch(dataChan, watcher.Duration)
	return dataChan
}

func (watcher *IOWatcher) watch(ch chan<- *WatchData, duration time.Duration) {
	defer close(ch)
	ticker := time.NewTicker(duration)
	oldStat := make(map[string]uint64)
	// 初始化oldStat
	stat, err := disk.IOCounters()
	for key, value := range stat {
		oldStat["read_count_"+key] = value.ReadCount
		oldStat["read_bytes_"+key] = value.ReadBytes
		oldStat["write_count_"+key] = value.WriteCount
		oldStat["write_bytes_"+key] = value.WriteBytes
	}
	for t := range ticker.C {
		select {
		case <-watcher.Done:
			ticker.Stop()
			break
		default:
			stat, err = disk.IOCounters()
			if err != nil {
				continue
			}
			fields := make(map[string]interface{})
			fd := duration.Seconds()
			for key, value := range stat {
				fields["read_count_"+key] = (float64(value.ReadCount) - float64(oldStat["read_count_"+key])) / fd
				fields["read_bytes_"+key] = (float64(value.ReadBytes) - float64(oldStat["read_bytes_"+key])) / fd
				fields["write_count_"+key] = (float64(value.WriteCount) - float64(oldStat["write_count_"+key])) / fd
				fields["write_bytes_"+key] = (float64(value.WriteBytes) - float64(oldStat["write_bytes_"+key])) / fd
				oldStat["read_count_"+key] = value.ReadCount
				oldStat["read_bytes_"+key] = value.ReadBytes
				oldStat["write_count_"+key] = value.WriteCount
				oldStat["write_bytes_"+key] = value.WriteBytes
			}
			ch <- &WatchData{
				Measurement: "io",
				Time:        t,
				Fields:      fields,
			}
		}
	}
}

func (watcher *IOWatcher) Close() {
	close(watcher.Done)
}

func NewIOWatcher(conf config.Conf) (*IOWatcher, error) {
	return &IOWatcher{
		Done:     make(chan struct{}),
		Duration: conf.Duration,
	}, nil
}

var IORegister = func(conf config.Conf) (string, Watcher, error) {
	wt, err := NewIOWatcher(conf)
	return "io", wt, err
}
